﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using Cysharp.Threading.Tasks;
using System.Threading;
using System.Text.RegularExpressions;
using System;

/// <summary>
/// 语言转文字
/// </summary>
public class BaiduASR
{
    private const string appId = "39375909";
    private const string appKey = "kGmDGGxNn8jqGdYAA9mHjLoL";
    private const string secretKey = "p2vnMUHdqbqsOHa0IjMj5yhR9GWiOlHh";
    private const int recordFrequency = 8000;
    private const int recordMaxLength = 10;

    private const int sampleSize = 128 ;

    private int trueLength = 0;

    private string accessToken = string.Empty;
    private string asrResult = string.Empty;

    private bool hasMic = false;
    private bool isRecording = false;
    private string micName = string.Empty;
    private double lastPressTimestamp = 0;

    private AudioClip saveAudioClip;

    /// <summary> 语言转文字回调  </summary>
    public event Action<string> onSucc;
    public event Action<string> onError;
    public event Action onNot;

    /// <summary> 麦克风峰值回调  </summary>
    public event Action<float> onVolume;



    private async UniTask<string> GetToken()
    {
    
        var uri =
           string.Format(
               "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id={0}&client_secret={1}",
               appKey, secretKey);
        using (UnityWebRequest unityWebRequest = UnityWebRequest.Get(uri))
        {
            await unityWebRequest.SendWebRequest();

            if (unityWebRequest.isDone)
            {
                Match match = Regex.Match(unityWebRequest.downloadHandler.text, @"access_token.:.(.*?).,");
                if (match.Success)
                {
                    //表示正则匹配到了accessToken
                    accessToken = match.Groups[1].ToString();
                    Debug.Log("accessToken " + accessToken);
                    Debug.Log("验证通过");
                }
                else
                {
                    Debug.Log("验证失败");
                }
            }
        }
        return accessToken;
    }

    private async void GetData()
    {
        //Debug.Log("accessToken :" + accessToken);
        if (string.IsNullOrEmpty(accessToken))
        {
            accessToken = await GetToken();
        }
        if (string.IsNullOrEmpty(accessToken)) return;
        asrResult = string.Empty;

        //处理当前录音数据为PCM16
        float[] samples = new float[recordFrequency * trueLength * saveAudioClip.channels];
        saveAudioClip.GetData(samples, 0);
        var samplesShort = new short[samples.Length];
        for (var index = 0; index < samples.Length; index++)
        {
            samplesShort[index] = (short)(samples[index] * short.MaxValue);
        }
        byte[] datas = new byte[samplesShort.Length * 2];
        Buffer.BlockCopy(samplesShort, 0, datas, 0, datas.Length);

        string url = string.Format("{0}?cuid={1}&token={2}", "https://vop.baidu.com/server_api", SystemInfo.deviceUniqueIdentifier, accessToken);

        WWWForm wwwForm = new WWWForm();
        wwwForm.AddBinaryData("audio", datas);

        using (UnityWebRequest unityWebRequest = UnityWebRequest.Post(url, wwwForm))
        {
            unityWebRequest.SetRequestHeader("Content-Type", "audio/pcm;rate=" + recordFrequency);

            await unityWebRequest.SendWebRequest();
            Debug.Log(unityWebRequest.error);
            if (string.IsNullOrEmpty(unityWebRequest.error))
            {
                asrResult = unityWebRequest.downloadHandler.text;
              
                if (Regex.IsMatch(asrResult, @"err_msg.:.success"))
                {
                    Match match = Regex.Match(asrResult, "result.:..(.*?)..]");
                    if (match.Success)
                    {
                        asrResult = match.Groups[0].ToString();

                        int startIndex = asrResult.IndexOf("[\"") + 2; // 找到 "[\" 的位置并加上 2，即中文引号的长度
                        int endIndex = asrResult.LastIndexOf("\"]"); // 找到 "\"]" 的位置
                        if (startIndex >= 0 && endIndex >= 0 && endIndex > startIndex)
                        {
                            string extractedText = asrResult.Substring(startIndex, endIndex - startIndex);
                            Debug.Log(extractedText);
                            onSucc?.Invoke(extractedText);
                        }
                        else
                        {
                            Debug.Log("无法提取文本");
                        }


                    }
                    else
                    {
                        onNot?.Invoke();
                    }
                }
                else
                {
                    asrResult = string.Empty;
                    onError?.Invoke(asrResult);
                }
            }
        }
    }

    private double GetTimestampOfNowWithMillisecond()
    {
        return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000;
    }

    private int EndRecord()
    {
        //if (hasMic == false || isRecording == false)
        //    return 0;

        return Mathf.CeilToInt((float)(GetTimestampOfNowWithMillisecond() - lastPressTimestamp) / 1000f);
    }

    public bool CheckMicrophone()
    {
        if (Microphone.devices.Length < 1) return false;else return true;
    }

    public void StartRecord()
    {
        //if (Microphone.devices.Length < 1) return;
        //if (hasMic == false || isRecording) return;
        lastPressTimestamp = GetTimestampOfNowWithMillisecond();
        saveAudioClip = null;
        saveAudioClip = Microphone.Start(null, false, recordMaxLength, recordFrequency);
        while (Microphone.GetPosition(micName) <= 0) { }
        isRecording = true;
        VolumeRealtime();
    }

    private async void VolumeRealtime()
    {
        while (isRecording)
        {
            await UniTask.Yield();
            float v = GetVolumeRealtime();
            onVolume?.Invoke(v);
        }
    }

    private float GetVolumeRealtime()
    {
        if(Microphone.IsRecording(null))
        {
            if (saveAudioClip == null) return 0f;
            float[] samples = new float[sampleSize];
            int startPosition = Microphone.GetPosition(null) - (sampleSize + 1);
            if(startPosition > samples.Length)
            {
                saveAudioClip.GetData(samples, startPosition);
                float levelMax = 0;
                for (int i = 0; i < samples.Length; i++)
                {
                    if (samples[i] > levelMax) levelMax = samples[i];
                }
                return levelMax * 100;
            }
        }
        return 0;

    }

    //松手调用该方法
    public void GetASR()
    {
        Microphone.End(null);
        isRecording = false;
        trueLength = EndRecord();
        if (trueLength > 1)
        {
            GetData();
           
        }
        else
        {
            onSucc?.Invoke("录音时间过短");
        }
    }
}
